/* 
 * Copyright (c) 2009, Giora Kosoi giorak@gmail.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Giora Kosoi ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Giora Kosoi BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef HANDLER_H
#define HANDLER_H

#include <sparrow/stable.h>
#include <sparrow/variant_headers.h>

struct MemberCallerInterface
{
    virtual ~MemberCallerInterface()
    {
    }

    virtual void operator()(void *)
    {
    }
};

template<class ObjectType, class ArgType>
class MemberCaller : public MemberCallerInterface
{
        ObjectType *o_;
        void (ObjectType::*member_function_)(ArgType *arg);
    public:
        MemberCaller(ObjectType *object, void (ObjectType::*member_function)(ArgType *arg))
            :   o_(object),
                member_function_(member_function)
        {
        }

        virtual ~MemberCaller()
        {
        }

        virtual void operator()(void *arg)
        {
            ArgType *a = static_cast<ArgType *>(arg);
            if(!a)
            {
                // log
            }
            (o_->*member_function_)(a);
        }

    private:
};

class Reactor;
class VariantSet;
class Handler
{
    public:
        virtual ~Handler();
        virtual void handle_input(int fd, uint64_t token);
        virtual void handle_output(int fd, uint64_t token);
        virtual void handle_error(int fd, uint64_t token);
        virtual void handle_timeout(uint64_t token);

        void push(int port, VariantSet *v);
        void push(const std::string &port, VariantSet *v);

        virtual Reactor *get_reactor(const std::nothrow_t &);
        virtual Reactor *get_reactor();

        static void connect_output(
                Handler *source, int source_port, 
                Handler *dest, int dest_port);
        static void connect_output(
                Handler *source, int source_port, 
                Handler *dest, const std::string &dest_port);
        static void connect_output(
                Handler *source, const std::string &source_port, 
                Handler *dest, int dest_port);
        static void connect_output(
                Handler *source, const std::string &source_port, 
                Handler *dest, const std::string &dest_port);

        void call_once();

    protected:
        Handler(Reactor *r);
        
        template<class HandlerType, class ArgType>
        void register_input(
                int port, 
                HandlerType *h, 
                void (HandlerType::*member_function)(ArgType *));

        template<class HandlerType, class ArgType>
        void register_input(
                const std::string &port, 
                HandlerType *h, 
                void (HandlerType::*member_function)(ArgType *));

        template<class HandlerType, class ArgType>
        void register_once(
                HandlerType *h, 
                void (HandlerType::*member_function)(ArgType *));

        size_t num_outputs();

    private:
        void add_output(MemberCallerInterface *caller, int port);
        void add_output(MemberCallerInterface *caller, const std::string &port);

        void add_input(MemberCallerInterface *caller, int port);
        void add_input(MemberCallerInterface *caller, const std::string &port);

        void add_once(MemberCallerInterface *caller);

        MemberCallerInterface *get_output(int port);
        MemberCallerInterface *get_output(const std::string &port);

        MemberCallerInterface *get_input(int port);
        MemberCallerInterface *get_input(const std::string &port);

        MemberCallerInterface *get_once(int index);

        static void delete_handler(void *p);

        Reactor *r_;
        VariantSet input_;
        VariantSet output_;
        VariantSet once_;
};

template<class HandlerType, class ArgType>
void Handler::register_input(int port, HandlerType *h, void (HandlerType::*member_function)(ArgType *))
{
    add_input(new MemberCaller<HandlerType, ArgType>(h, member_function), port);
}

template<class HandlerType, class ArgType>
void Handler::register_input(const std::string &port, HandlerType *h, void (HandlerType::*member_function)(ArgType *))
{
    add_input(new MemberCaller<HandlerType, ArgType>(h, member_function), port);
}

template<class HandlerType, class ArgType>
void Handler::register_once(HandlerType *h, void (HandlerType::*member_function)(ArgType *))
{
    h->get_reactor()->add_once(new MemberCaller<HandlerType, ArgType>(h, member_function));
}


#endif // HANDLER_H

